//  Copyright (C) 2014 Xiande (Triston) Cao

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef CVSIE_SIMULATION_OPTION_HPP
#define CVSIE_SIMULATION_OPTION_HPP

namespace cvsie {
  enum LengthUnit {
    nm = -9, um = -6, mm = -3, cm = -2, meter=0, km = 3, inch = 4, foot = 5
  };
  double GetScaleToMeterByLengthUnit(const LengthUnit &length_unit);

  enum MeshFileType {
    MESH27 = 0, ABAQUS = 1
  };

  enum PolorizationBiStatic {
    VV = 0, HV = 1, VH = 2, HH = 3, ALL = 4
  };

  enum RadarConfiguration {
    kMonoStatic = 1, kBiStatic = 2
  };

  enum SolverOption {
    kDirect = 0, kIterative = 1
  };

  enum IterativeSolverType {
    CG = 0, CGS, BiCG, BiCGSTAB1, BiCGSTAB2
  };

  class CIterativeSolverOption {
    public:
      IterativeSolverType type;              // iterative solver type
      int                 max_num_iteration; // Maximum number of iterations
      double              tolerance;         // the tolerance
  };


  class CRangeOption {
    private: 
      int    num_step; // number of steps
      double start;    // lower bound (start) of the range
      double end;      // upper bound (end) of the range
    public:
      CRangeOption();
      CRangeOption(int _num_step, double _start, double _end) : 
        num_step(_num_step), start(_start), end(_end) { }

    public:

      int GetNumStep() const         { return num_step; }
      void SetNumStep(int _num_step) { num_step = _num_step; }

      double GetStart() const        { return start; }
      void SetStart(double _start)   { start = _start; }

      double GetEnd() const          { return end; }
      void SetEnd(double _end)       { end = _end; }

      void SetAllOptions(int _num_step, double _start, double _end) {
        num_step = _num_step;
        start    = _start;
        end      = _end;
      }
      void GetAllOptions(int &_num_step, double &_start, double &_end) {
        _num_step = num_step;
        _start    = start;
        _end      = end;
      }

      int ReadOptionFromLine(const char *line);
      int WriteOptionToLine(char *line);

      int ReadOptionFromString(const string &str);
      int WriteOptionToString(string &str);

      int CheckValidity() 
      {
        if (num_step < 1) {
          return -1;
        }
        return 0;
      }
  };


  class CSimulationOptions {
    private:
      LengthUnit   length_unit;         // the length unit
      CRangeOption frequency;           // the frequency option
      CRangeOption incident_theta;      // incident polor angle in rad
      CRangeOption incident_phi;        // incident azimuthal angle in rad
      CRangeOption scattered_theta;     // scattered polor angle in rad
      CRangeOption scattered_phi;       // scattered azimuthal angle in rad

      // consolidate tolerance, when the distance of two point is less 
      // than the tolerance, it will merged into one point
      double consolidate_tolerance;     // consolidate tolerance

      // output options
      bool output_matrix;               // output matrix to a file
      bool output_rhs;                  // output right hand side to a file
      bool output_rcs;                  // output RCS to a file

    public:
      void SetLengthUnit(const LengthUnit & _length_unit) {
        length_unit = _length_unit;
      }
      LengthUnit GetLengthUnit() const { return length_unit; }

      void SetFrequencyOption(const CRangeOption &frequency_option);
      void GetFrequencyOption(CRangeOption &frequency_option);

      int ReadFrequencyOptionFromLine(const char *str); 
      int ReadFrequencyOptionFromString(const string &str); 
      int WriteFrequencyOptionToString(string &str); 

      void SetIncidentThetaOption(const CRangeOption &incident_theta_option);
      void GetIncidentThetaOption(CRangeOption &incident_theta_option);

      void SetIncidentPhiOption(const CRangeOption &incident_phi_option);
      void GetIncidentPhiOption(CRangeOption &incident_phi_option);

      void SetScatteredThetaOption(const CRangeOption &scattered_theta_option);
      void GetScatteredThetaOption(CRangeOption &scattered_theta_option);

      void SetScatteredPhiOption(const CRangeOption &scattered_phi_option);
      void GetScatteredPhiOption(CRangeOption &scattered_phi_option);

      int ReadOptionsFromFile(const string &file_name);
      int WriteOptionsToFile(string &file_name);
  };

} // namespace cvsie

#endif
